package com.rengwuxian.coursecoroutines._4_flow

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEmpty
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlin.coroutines.EmptyCoroutineContext

/**
 * onStart()等全流程监听系列操作符
 * onStart()、onCompletion()、onEmpty()
 *
 * 监听flow的开始和结束
 * onStart()：负责监听Flow的收集流程的开始事件的，在collect调用之后，正式生产之前
 *            确切的说，在调用上游的collect之前，onStart()的代码块就被执行了。
 *            连续调用两个onStart(),下面的onStart()会先执行。
 *            把上游的emit()用try/catch包起来，捕获不到onStart()中的异常。
 *            但是catch()操作符可以抓住。
 * catch()捕获的是整个上游的异常，不管是生产过程中，还是生产过程前后的异常。
 *
 * onCompletion()：负责监听Flow的结束，所有的数据发送完了。
 *                 不管是正常结束，还是异常结束。
 *                 大括号中的参数Throwable，如果flow是正常结束就是null，否则就是对应的异常。
 *                 虽然能拿到异常，但是不拦截异常，异常会继续往下抛。
 *
 * onEmpty()：监听Flow是否为空，即没有数据发送。需要是正常结束。异常结束就不会触发。
 *
 * 本例子输出：
 * onStart 2
 * onStart 1
 * onCompletion: java.lang.RuntimeException: onStart error
 * catch: java.lang.RuntimeException: onStart error
 */
fun main() = runBlocking<Unit> {
  val scope = CoroutineScope(EmptyCoroutineContext)
  val flow1 = flow {
    try {
      for (i in 1..5) {
        emit(i)
      }
    } catch (e: Exception) {
      println("try / catch: $e")
    }
  }.onStart {
    println("onStart 1")
    throw RuntimeException("onStart error")
  }
    .onStart { println("onStart 2") }
    .onCompletion {
      println("onCompletion: $it")
    }.onEmpty { println("onEmpty") }
    .catch { println("catch: $it") }
  scope.launch {
    flow1.collect {
      println("Data: $it")
    }
  }
  delay(10000)
}